Part 9 - 加密程序简介

信不信由你,有可能使用加密数据进行计算。换句话说,可以在程序中对所有变量进行加密的情况下运行该程序!

在本教程中,我们将逐步介绍加密计算的基本工具。特别地,我们将集中于一种流行的方法,称为安全多方计算。在本课程中,我们将学习如何构建一个可以对加密数字执行计算的加密计算器。

作者:

参考文献:

中文版译者:

第1步: 使用安全的多方计算进行加密

乍一看,SMPC(Secure Multi-Party Computation,安全多方计算)是一种非常奇怪的“加密”形式。 每个值都被分成多个“共享”,而不是使用公共/私有密钥对变量进行加密,每个共享都像私有密钥一样工作。 通常,这些“份额”将分配给2个或更多owners。 因此,为了解密变量,所有所有者必须同意允许解密。 本质上,每个人都有一个私钥。

Encrypt()

因此,假设我们要“加密”变量“x”,可以通过以下方式进行。

加密不使用浮点数或实数,而是在称为整数商环的数学空间中进行,该空间基本上是介于0Q-1之间的整数 ,其中Q是质数,并且“足够大”,以便该空间可以包含我们在实验中使用的所有数字。 实际上,给定值x整数,我们将x%Q放入环中。 (这就是为什么我们避免使用数字“ x”> Q”的原因)。


In [1]:
Q = 1234567891011

In [2]:
x = 25

In [3]:
import random

def encrypt(x):
    share_a = random.randint(-Q,Q)
    share_b = random.randint(-Q,Q)
    share_c = (x - share_a - share_b) % Q
    return (share_a, share_b,  share_c)

In [4]:
encrypt(x)


Out[4]:
(-446602070667, 514935564586, 1166234397117)

如您所见,我们将变量x分为3个不同的份额,可以将其发送给3个不同的所有者。

Decrypt()

如果我们想解密这3个份额,我们可以简单地将它们加在一起并取结果的模数(模Q)。


In [5]:
def decrypt(*shares):
    return sum(shares) % Q

In [6]:
a,b,c = encrypt(25)

In [7]:
decrypt(a, b, c)


Out[7]:
25

重要的是,请注意,如果我们尝试仅使用两个共享进行解密,则解密将不起作用!


In [8]:
decrypt(a, b)


Out[8]:
1106336185349

因此,我们需要所有所有者参与才能解密该值。 通过这种方式,shares就像私钥一样,所有私钥都必须存在才能解密值。

第2步: 使用SMPC的基本算法

然而,安全多方计算的真正非凡特性是能够在变量被加密的同时进行计算。让我们在下面演示简单的加法。


In [9]:
x = encrypt(25)
y = encrypt(5)

In [10]:
def add(x, y):
    z = list()
    # 第一个工作机将其共享分片相加
    z.append((x[0] + y[0]) % Q)
    
    # 第二个工作机将其共享分片相加
    z.append((x[1] + y[1]) % Q)
    
    # 第三个工作机将其共享分片相加
    z.append((x[2] + y[2]) % Q)
    
    return z

In [11]:
decrypt(*add(x,y))


Out[11]:
30

成功!!!

您做到了!如果每个工作机(分别)将其份额加在一起,则所得份额将解密为正确的值(25 + 5 == 30)。

事实证明,存在SMPC协议,该协议可以允许针对以下操作进行此加密计算:

  • 加法(我们刚刚看到)
  • 乘法
  • 比较

并使用这些基本的基础原语,我们可以执行任意计算!!!

在下一节中,我们将学习如何使用PySyft库执行这些操作!

第3步: 使用PySyft的SMPC

在前面的部分中,我们概述了关于SMPC应该起作用的一些基本直觉。但是,实际上,在编写加密程序时,我们不需要自己亲自编写所有原始操作。因此,在本节中,我们将逐步介绍如何使用PySyft进行加密计算的基础知识。特别是,我们将集中精力于如何执行前面提到的3个原语:加法,乘法和比较。

首先,我们需要创建一些虚拟工作机(希望您现在对我们之前的教程已经很熟悉了)。


In [12]:
import torch
import syft as sy
hook = sy.TorchHook(torch)

bob = sy.VirtualWorker(hook, id="bob")
alice = sy.VirtualWorker(hook, id="alice")
bill = sy.VirtualWorker(hook, id="bill")

基础的加/解密

加密就像获取任何PySyft张量并调用.share()一样简单。解密就像在共享变量上调用.get()一样简单


In [13]:
x = torch.tensor([25])

In [14]:
x


Out[14]:
tensor([25])

In [15]:
encrypted_x = x.share(bob, alice, bill)

In [16]:
encrypted_x.get()


Out[16]:
tensor([25])

内省加密值

如果我们仔细观察Bob,Alice和Bill的工作机,我们可以看到创建的份额!


In [17]:
bob._objects


Out[17]:
{}

In [18]:
x = torch.tensor([25]).share(bob, alice, bill)

In [19]:
# Bob's share
bobs_share = list(bob._objects.values())[0]
bobs_share


Out[19]:
tensor([-4735902090614154118])

In [20]:
# Alice's share
alices_share = list(alice._objects.values())[0]
alices_share


Out[20]:
tensor([-1605017515133521854])

In [21]:
# Bill's share
bills_share = list(bill._objects.values())[0]
bills_share


Out[21]:
tensor([6340919605747675997])

如果愿意,我们可以使用我们之前讨论的同样的方法解密这些值!!!


In [22]:
(bobs_share + alices_share + bills_share)


Out[22]:
tensor([25])

如您所见,当我们调用.share()时,它只是将值分割成3股,并向每一方发送了一份!

加密加法

现在您看到我们可以对基础值执行加法了!API的构造使我们可以像执行普通的PyTorch张量那样简单地执行算法。


In [23]:
x = torch.tensor([25]).share(bob,alice)
y = torch.tensor([5]).share(bob,alice)

In [24]:
z = x + y
z.get()


Out[24]:
tensor([30])

In [25]:
z = x - y
z.get()


Out[25]:
tensor([20])

加密乘法

为了进行乘法运算,我们需要一个额外的一方负责连续生成随机数(而不与其他任何一方串通)。 我们称此人为“密码提供者”。 对于所有密集用途,加密提供者只是一个额外的VirtualWorker,但必须承认加密提供者不是“所有者”,因为他/她不拥有股份,而是需要信任才能避免串通的人与任何现有股东。


In [26]:
crypto_provider = sy.VirtualWorker(hook, id="crypto_provider")

In [27]:
x = torch.tensor([25]).share(bob,alice, crypto_provider=crypto_provider)
y = torch.tensor([5]).share(bob,alice, crypto_provider=crypto_provider)

In [28]:
# multiplication

z = x * y
z.get()


Out[28]:
tensor([125])

而且可以执行矩阵乘法


In [29]:
x = torch.tensor([[1, 2],[3,4]]).share(bob,alice, crypto_provider=crypto_provider)
y = torch.tensor([[2, 0],[0,2]]).share(bob,alice, crypto_provider=crypto_provider)

In [30]:
# matrix multiplication

z = x.mm(y)
z.get()


Out[30]:
tensor([[2, 4],
        [6, 8]])

加密比较

私有值之间的私有比较也是可能的。 我们在这里依赖SecureNN协议,其详细信息可以在这里找到。比较的结果也是私有共享张量。


In [31]:
x = torch.tensor([25]).share(bob,alice, crypto_provider=crypto_provider)
y = torch.tensor([5]).share(bob,alice, crypto_provider=crypto_provider)

In [32]:
z = x > y
z.get()


Out[32]:
tensor([1])

In [33]:
z = x <= y
z.get()


Out[33]:
tensor([0])

In [34]:
z = x == y
z.get()


Out[34]:
tensor([0])

In [35]:
z = x == y + 20
z.get()


Out[35]:
tensor([1])

您还可以执行求最值操作


In [36]:
x = torch.tensor([2, 3, 4, 1]).share(bob,alice, crypto_provider=crypto_provider)
x.max().get()


Out[36]:
tensor([4])

In [37]:
x = torch.tensor([[2, 3], [4, 1]]).share(bob,alice, crypto_provider=crypto_provider)
max_values, max_ids = x.max(dim=0)
max_values.get()


Out[37]:
tensor([4, 3])

恭喜!!! 是时候加入社区了!

祝贺您完成本笔记本教程! 如果您喜欢此方法,并希望加入保护隐私、去中心化AI和AI供应链(数据)所有权的运动,则可以通过以下方式做到这一点!

给 PySyft 加星

帮助我们的社区的最简单方法是仅通过给GitHub存储库加注星标! 这有助于提高人们对我们正在构建的出色工具的认识。

加入我们的 Slack!

保持最新进展的最佳方法是加入我们的社区! 您可以通过填写以下表格来做到这一点http://slack.openmined.org

加入代码项目!

对我们的社区做出贡献的最好方法是成为代码贡献者! 您随时可以转到PySyft GitHub的Issue页面并过滤“projects”。这将向您显示所有概述,选择您可以加入的项目!如果您不想加入项目,但是想做一些编码,则还可以通过搜索标记为“good first issue”的GitHub问题来寻找更多的“一次性”微型项目。

捐赠

如果您没有时间为我们的代码库做贡献,但仍想提供支持,那么您也可以成为Open Collective的支持者。所有捐款都将用于我们的网络托管和其他社区支出,例如黑客马拉松和聚会!

OpenMined's Open Collective Page


In [ ]: